﻿namespace SS.Common.Collection
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Represent a thread safe list
    /// </summary>
    /// <typeparam name="T">
    /// The type of elements in the list
    /// </typeparam>
    public sealed class SyncList<T> : ISyncList<T>
    {
        #region Fields

        /// <summary>
        /// List to contains data object
        /// </summary>
        private readonly IList<T> _listData;

        /// <summary>
        /// Object to synchronize
        /// </summary>
        private readonly object _syncObj = new object();

        #endregion

        #region Constructor

        /// <summary>
        /// Construct a empty new SyncList instance
        /// </summary>
        public SyncList()
        {
            this._listData = new List<T>();
        }

        /// <summary>
        /// Construct a empty new SyncList instance
        /// </summary>
        /// <param name="capacity">Capacity</param>
        public SyncList(int capacity)
        {
            this._listData = new List<T>(capacity);
        }

        /// <summary>
        /// Construct a new SyncList that contains elements copied from the specified collection
        /// </summary>
        /// <param name="collection">
        /// The collection whose elements are copied to the new list
        /// </param>
        public SyncList(IEnumerable<T> collection)
        {
            this._listData = new List<T>(collection);
        }

        #endregion

        #region IList<T> Members

        /// <summary>
        ///  Determines the index of a specific item
        /// </summary>
        /// <param name="item">
        /// The object to locate
        /// </param>
        /// <returns>
        /// The index of item if found in the list; otherwise, -1.
        /// </returns>
        public int IndexOf(T item)
        {
            lock (this._syncObj)
            {
                return this._listData.IndexOf(item);
            }
        }

        /// <summary>
        /// Insert an item as the specified index
        /// </summary>
        /// <param name="index">
        /// The zero-based index at which item should be inserted
        /// </param>
        /// <param name="item">
        /// The object to insert
        /// </param>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Index is not valid
        /// </exception>
        public void Insert(int index, T item)
        {
            lock (this._syncObj)
            {
                this._listData.Insert(index, item);
            }
        }

        /// <summary>
        /// Removes the item at the specified index
        /// </summary>
        /// <param name="index">
        /// The zero-based index of the item to remove
        /// </param>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Index is not valid
        /// </exception>
        public void RemoveAt(int index)
        {
            lock (this._syncObj)
            {
                this._listData.RemoveAt(index);
            }
        }

        /// <summary>
        ///  Gets or sets the element at the specified index
        /// </summary>
        /// <param name="index">
        /// The zero-based index of the element to get or set
        /// </param>
        /// <returns>
        /// The element at the specified index
        /// </returns>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Index is not valid
        /// </exception>
        public T this[int index]
        {
            get
            {
                return this._listData[index];
            }

            set
            {
                lock (this._syncObj)
                {
                    this._listData[index] = value;
                }
            }
        }

        #endregion

        #region ICollection<T> Members

        /// <summary>
        ///  Adds an item
        /// </summary>
        /// <param name="item">
        /// The object to add
        /// </param>
        public void Add(T item)
        {
            lock (this._syncObj)
            {
                this._listData.Add(item);
            }
        }

        /// <summary>
        /// Removes all items
        /// </summary>
        public void Clear()
        {
            lock (this._syncObj)
            {
                this._listData.Clear();
            }
        }

        /// <summary>
        /// Determines whether the list contains a specific value
        /// </summary>
        /// <param name="item">
        /// The object to locate
        /// </param>
        /// <returns>
        /// True if found
        /// </returns>
        public bool Contains(T item)
        {
            lock (this._syncObj)
            {
                return this._listData.Contains(item);
            }
        }

        /// <summary>
        /// Copy the elements of the list to an array, starting at a particular array index
        /// </summary>
        /// <param name="array">
        /// The one-dimensional array that is the distination of the elements copied from SyncDictionary
        /// </param>
        /// <param name="arrayIndex">The zero-based index in array at which copying begins</param>
        /// <exception cref="ArgumentNullException">Array is null</exception>
        /// <exception cref="ArgumentOutOfRangeException">arrayIndex is less than 0</exception>
        /// <exception cref="ArgumentException">
        /// array is multidimensional or arrayIndex is equal to or greater than the length of array 
        /// or the number of elements in the source System.Collections.Generic.ICollection of T
        /// is greater than the available space from arrayIndex to the end of the destination
        /// array or type T cannot be cast automatically to the type of the destination array.
        /// </exception>
        public void CopyTo(T[] array, int arrayIndex)
        {
            lock (this._syncObj)
            {
                this._listData.CopyTo(array, arrayIndex);
            }
        }

        /// <summary>
        /// Gets the number of elements in the list
        /// </summary>
        public int Count
        {
            get
            {
                return this._listData.Count;
            }
        }

        /// <summary>
        /// Get a value indicating whether the list is read-only
        /// Always false
        /// </summary>
        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Removes the first occurrence of a specific object from the list
        /// </summary>
        /// <param name="item">
        /// The object to remove
        /// </param>
        /// <returns>
        /// True if item was removed successfully
        /// This method also returns false if item is not found
        /// </returns>
        public bool Remove(T item)
        {
            lock (this._syncObj)
            {
                return this._listData.Remove(item);
            }
        }

        #endregion

        #region IEnumerable<T> Members

        /// <summary>
        /// Returns an enumerator that iterates through the collection
        /// </summary>
        /// <returns>
        /// A Enumerator that can be used to iterate through the collection
        /// </returns>
        public IEnumerator<T> GetEnumerator()
        {
            lock (this._syncObj)
            {
                // Create a snapshot for the collection
                //T[] array = new T[this.listData.Count];
                //this.listData.CopyTo(array, 0);
                //return Array.AsReadOnly(array).GetEnumerator();

                return new List<T>(this._listData).GetEnumerator();
            }
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that iterates through the collection
        /// </summary>
        /// <returns>
        /// A Enumerator that can be used to iterate through the collection
        /// </returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            //lock (this.syncObj)
            //{
            return this.GetEnumerator();
            //}
        }

        #endregion

        #region ISyncList<T> Members

        /// <summary>
        /// Get/Set synchronize object
        /// </summary>
        public object SyncObj
        {
            get
            {
                return this._syncObj;
            }
        }

        /// <summary>
        /// Sort all elements in the list
        /// </summary>
        /// <param name="comparer">The comparer</param>
        /// <returns>
        /// True if succeeds, No Exception here
        /// </returns>
        public bool TrySort(IComparer<T> comparer)
        {
            try
            {
                lock (this._syncObj)
                {
                    ((List<T>)this._listData).Sort(comparer);
                }

                return true;
            }
            catch
            {
                return false;
            }            
        }

        #endregion
    }
}


